#include "util.h"
#include <stdarg.h>
#include <memory>
#include <algorithm>
#include <chrono>
#include <fcntl.h>
#include <iconv.h>
using namespace std;


string util::format(const char* fmt, ...) {
    char buffer[500];
    unique_ptr<char[]> release1;
    char* base;
    for (int iter = 0; iter < 2; iter++) {
        int bufsize;
        if (iter == 0) {
            bufsize = sizeof(buffer);
            base = buffer;
        } else {
            bufsize = 30000;
            base = new char[bufsize];
            release1.reset(base);
        }
        char* p = base;
        char* limit = base + bufsize;
        if (p < limit) {
            va_list ap;
            va_start(ap, fmt);
            p += vsnprintf(p, limit - p, fmt, ap);
            va_end(ap);
        }
        // Truncate to available space if necessary
        if (p >= limit) {
            if (iter == 0) {
                continue;       // Try again with larger buffer
            } else {
                p = limit - 1;
                *p = '\0';
            }
        }
        break;
    }
    return base;
}

int64_t util::timeMicro() {
    chrono::time_point<chrono::system_clock> p = chrono::system_clock::now();
    return chrono::duration_cast<chrono::microseconds>(p.time_since_epoch()).count();
}
int64_t util::steadyMicro() {
    chrono::time_point<chrono::steady_clock> p = chrono::steady_clock::now();
    return chrono::duration_cast<chrono::microseconds>(p.time_since_epoch()).count();
}

std::string util::readableTime(time_t t) {
    struct tm tm1;
    localtime_r(&t, &tm1);
    return format("%04d-%02d-%02d %02d:%02d:%02d",
        tm1.tm_year+1900, tm1.tm_mon, tm1.tm_mday, tm1.tm_hour, tm1.tm_min, tm1.tm_sec);
}

int util::addFdFlag(int fd, int flag) {
    int ret = fcntl(fd, F_GETFD);
    return fcntl(fd, F_SETFD, ret | flag);
}
int code_convert(const char* from_charset, const char* to_charset, char* inbuf,
	size_t inlen, char* outbuf, size_t outlen);
char* g2u(char *inbuf)
{

	int nOutLen = 2 * (strlen(inbuf) + 1);
	if (nOutLen <= 0)
	{
		return NULL;
	}
	char* szOut = new char[nOutLen];
	if (-1 == code_convert("gb18030", "utf-8", inbuf, strlen(inbuf), szOut, nOutLen))
	{
		delete  szOut;
		szOut = NULL;
	}
	return szOut;
}

string util::GBToUTF8(const string& strGb)
{
	string strUTF8;
	char * szValue = g2u((char *)strGb.c_str());
	if (szValue)
	{
		strUTF8.append(szValue);
		delete[] szValue;
	}
	return strUTF8;
}

int code_convert(const char* from_charset, const char* to_charset, char* inbuf,
	size_t inlen, char* outbuf, size_t outlen)
{
	iconv_t cd;
	char** pin = &inbuf;
	char** pout = &outbuf;
	cd = iconv_open(to_charset, from_charset);
	if (cd == 0)
		return -1;
	memset(outbuf, 0, outlen);
	//(iconv_t cd, const char* * inbuf, size_t *inbytesleft, char* * outbuf, size_t *outbytesleft);
	if (iconv(cd, pin, (size_t*)&inlen, pout, (size_t*)&outlen) == -1)//in 64 bit,size_t != int
	{
		iconv_close(cd);
		return -1;
	}
	iconv_close(cd);
	return 0;
}

char* util::u2g(char *inbuf)
{
	int nOutLen = 2 * (strlen(inbuf) + 1);
	if (nOutLen <= 0) return NULL;

	char* szOut = new char[nOutLen];
	//char* szOut = (char*)malloc(nOutLen);
	if (-1 == code_convert("utf-8", "gb18030", inbuf, strlen(inbuf), szOut, nOutLen))
	{
		delete szOut;
		szOut = NULL;
	}
	return szOut;
}